Moleculer 內建了幾種負載平衡策略,如果服務在多個節點實例運作, ServiceRegistry 可以使用這些策略來從活躍的節點中選擇某個節點。
如果想要使用內建的負載平衡策略,可以在 registry 內設定 strategy ,可以是一個字串名稱或是客製化的 Strategy 類別。
RoundRobin 是採用 Round-Robin DNS 的方式,以循環的方式逐個輪替[2] 。
範例:
moleculer.config.js
module.exports = {
    registry: {
        strategy: "RoundRobin"
    }
};
Random 策略會隨機選擇一個可用的節點。
範例:
moleculer.config.js
module.exports = {
    registry: {
        strategy: "Random"
    }
};
CpuUsage 策略會選擇 CPU 使用率最低的節點。但由於節點清單可能非常大,因此該策略會在列表中隨機取樣,並選擇 CPU 使用率最低的節點,而不是對整個節點清單去選擇最低的節點。
範例:
| 名稱 | 類型 | 預設值 | 說明 | 
|---|---|---|---|
sampleCount | 
<Number> | 3 | 
取樣點的數量。若要關閉採樣請設為 0 。 | 
lowCpuUsage | 
<Number> | 10 | 
低 CPU 使用率百分比(%)。CPU 的使用率如果低於此百分比則立即選擇此節點。 | 
moleculer.config.js
module.exports = {
    registry: {
        strategy: "CpuUsage",
        strategyOptions: {
            sampleCount: 3,
            lowCpuUsage: 10
        }
    }
};
Latency 策略會定時發送 ping 來測試節點延遲時間,再選擇網路延遲最低的節點。由於節點清單可能非常大,因此該策略會在列表中隨機取樣,而不是對整個節點清單去選擇最低的節點。
範例:
| 名稱 | 類型 | 預設值 | 說明 | 
|---|---|---|---|
sampleCount | 
<Number> | 5 | 
取樣點的數量。若要關閉採樣請設為 0 。 | 
lowLatency | 
<Number> | 10 | 
低延遲(毫秒)。延遲時間如果低於該值則立即選擇此節點。 | 
collectCount | 
<Number> | 5 | 
單個節點保留的取樣資料總數,供計算平均延遲使用。 | 
pingInterval | 
<Number> | 10 | 
定時發送 Ping 的間隔時間。如果你的節點清單非常大,建議增加間隔時間。 | 
moleculer.config.js
module.exports = {
    registry: {
        strategy: "Latency",
        strategyOptions: {
            sampleCount: 15,
            lowLatency: 20,
            collectCount: 10,
            pingInterval: 15
        }
    }
};
Shard 策略是基於 Consistent Hashing 演算法,它可以根據 params 或 meta context 的鍵值來請求路由到節點。換句話說就是相同鍵值的請求,將會被路由到相同的節點上。
範例:以 params context 的 name 進行分片。
moleculer.config.js
module.exports = {
    registry: {
        strategy: "Shard",
        strategyOptions: {
            shardKey: "name"
        }
    }
};
範例:以 meta context 的 user.id 進行分片
注意,以
metacontext 進行分片時,必須在前面加上#符號 ,實際執行時會忽略#。
moleculer.config.js
module.exports = {
    registry: {
        strategy: "Shard",
        strategyOptions: {
            shardKey: "#user.id"
        }
    }
};
範例:選項設定方式
| 名稱 | 類型 | 預設值 | 說明 | 
|---|---|---|---|
shardKey | 
<String> | null | 
分片的鍵名稱。 | 
vnodes | 
<Number> | 10 | 
虛擬節點數量。 | 
ringSize | 
<Number> | 2^32 | 
環的大小。 | 
cacheSize | 
<Number> | 1000 | 
快取大小。 | 
moleculer.config.js
module.exports = {
    registry: {
        strategy: "Shard",
        strategyOptions: {
            shardKey: "#user.id",
            vnodes: 10,
            ringSize: 1000,
            cacheSize: 1000
        }
    }
};
你可以在 Actions 或事件設定負載平衡策略來覆蓋全域的負載平衡策略。
範例:對 hello Action 設定 Shard 策略來覆蓋全域的 RoundRobin 策略。
moleculer.config.js
module.exports = {
    registry: {
        strategy: "RoundRobin"
    }
};
greeter.service.js
module.exports = {
	name: "greeter",
	actions: {
		hello: {
			params: {
				name: "string"
			},
			strategy: "Shard",
			strategyOptions: {
				shardKey: "name"
			},
            handler(ctx) {
				return `Hello ${ctx.params.name}`;
			}
		}
	}
};
你也可以自己建立客製化策略,創建一個策略類別繼承自 BaseStrategy ,官方建議參考隨機策略的原始碼[4] 來實作 select 方法。
範例:建立客製化策略
my-strategy.js
const BaseStrategy = require("moleculer").Strategies.Base;
class MyStrategy extends BaseStrategy {
    select(list, ctx) { /*...*/ }
}
module.exports = MyStrategy;
範例:使用客製化策略
moleculer.config.js
const MyStrategy = require("./my-strategy");
const Strategies = require("moleculer").Strategies
// 註冊一個客製化策略
Strategies.register("myCustomStrategy", MyStrategy)
module.exports = {
    registry: {
        // 由於客製化策略已被註冊,可以直接填入字串名稱
        strategy: "myCustomStrategy"
    }
};
ServiceBroker 會優先嘗試使用本地的服務實例(如果存在)來減少網路延遲。如果目標服務在本地的 Broker 為可用,則配置的策略將會被跳過, Broker 將始終優先採用本地服務。你可以在選項中設定 preferLocal: false 以關閉此邏輯。
moleculer.config.js
module.exports = {
    registry: {
        preferLocal: false
    }
};
[1] Load balancing, https://moleculer.services/docs/0.14/balancing.html
[2] Round-robin DNS, https://en.wikipedia.org/wiki/Round-robin_DNS
[3] Consistent Hashing, https://www.toptal.com/big-data/consistent-hashing
[4] Random strategy, https://github.com/moleculerjs/moleculer/blob/master/src/strategies/random.js